package com.wave.gate.task;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.norco.API.NorcoAPI;
import com.wave.gate.dto.FaceMessage;
import com.wave.gate.dto.GatePassRecord;
import com.wave.gate.enums.*;
import com.wave.gate.init.InitBaseInfo;
import com.wave.gate.mqtt.client.MqttSendClient;
import com.wave.gate.util.*;
import com.wave.gate.vo.GatePassSetVo;
import com.wave.gate.vo.GatePassWeightParamVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.wave.gate.util.GuavaCache.*;

@Slf4j
public class Server {
    private static Map<String, Socket> clients = null;   //存放所有访问服务器的客户端和其用户名

    public Server() {
        clients = new HashMap<>();
        try {
            //1-初始化
            int port = 4000;
            ServerSocket server_socket = new ServerSocket(port);   //创建服务器
            //线程
            Map<String, Thread> tasks = new HashMap<>();
            //2-每次接收一个客户端请求连接时都启用一个线程处理
            while (true) {
                //accept方法一直阻塞直到接收到一个客户端的请求 并返回该客户端的套接字socket
                Socket client_socket = server_socket.accept();
                /*PrintWriter out = new PrintWriter(client_socket.getOutputStream());
                Map<String, String> responseMap = new HashMap<String, String>();
                responseMap.put("code", "6");
                responseMap.put("message", "");
                String responseStr = JSON.toJSONString(responseMap) + "###";
                out.write(responseStr);
                out.flush();*/
                //判断该客户端是否第一次访问
                String ipaddr = client_socket.getInetAddress().toString().replace("/", "");
                clients.put(ipaddr, client_socket);
                log.info("人脸机" + ipaddr + "已连接-53");
                //开启新线程处理客户端的请求
                FaceRecognitionLongTaskInner faceRecognitionLongTaskInner = new FaceRecognitionLongTaskInner(client_socket);
                String jobName = "face-" + ipaddr;
                faceRecognitionLongTaskInner.setName(jobName);
                faceRecognitionLongTaskInner.start();
                Thread thread = tasks.get(jobName);
                if (thread != null) {
                    thread.interrupt();
                }
                tasks.put(jobName, faceRecognitionLongTaskInner);
                log.info(faceRecognitionLongTaskInner.getName() + "已启动-64");
                showUserList();
            }
        } catch (Exception e) {
            log.error("server run error:[{}]", e.getMessage(), e);
        }
    }

    public static String bytesToHexString(byte[] b) {
        StringBuilder sbu = new StringBuilder();
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sbu.append(hex.toUpperCase());
        }
        return sbu.toString();
    }

    public static void main(String[] args) {
        byte b = -38;
        System.out.println(Byte.toUnsignedInt(b));
    }

    /**
     * 启用一个线程处理一个客户端的请求
     */
    @Component
    private class FaceRecognitionLongTaskInner extends Thread {
        private final Socket client_socket;
        @Value("${conveyer.ip}")
        public String conveyerIp;
        @Value("${conveyer.port}")
        public int conveyerPort;
        MqttSendClient mqttSendClient = /*ApplicationContextProvider.getBean(MqttSendClient.class)*/null;
        ThreadPoolTaskExecutor threadPoolTaskExecutor = /*ApplicationContextProvider.getBean(ThreadPoolTaskExecutor.class)*/null;

        public FaceRecognitionLongTaskInner(Socket client_socket) {
            this.client_socket = client_socket;
        }

        @Override
        public void run() {
            GatePassSetVo gatePassSetVo = GuavaCache.PASSSET_CACHE.getIfPresent("passsetipInfo");
            //A门人脸机IP
            String faceAIp = gatePassSetVo.getInFaceIp();
            //B门人脸机IP
            String faceBIp = gatePassSetVo.getOutFaceIp();
            //A门闸机IP
            String gateAIp = gatePassSetVo.getInGateIp();
            //A门闸机端口
            int gateAPort = 502;
            //B门闸机IP
            String gateBIp = gatePassSetVo.getOutGateIp();
            //B门闸机端口
            int gateBPort = 502;

            /*// 创建mNorcoAPI对象
            NorcoAPI mNorcoAPI = NorcoAPI.norcoAPICreate();
            // 释放一次(使用后未释放的情况)
            //金属探测门
            int gpioNumber_metal_detect = 122;
            mNorcoAPI.hwctrl_gpioUnExport(gpioNumber_metal_detect);
            // 导出GPIO
            boolean isSuccess = mNorcoAPI.hwctrl_gpioExport(gpioNumber_metal_detect);
            log.info("in hwctrl_gpioExport isSuccess=" + isSuccess);
            // 配置为输入引脚
            isSuccess = mNorcoAPI.hwctrl_gpioDirection(gpioNumber_metal_detect, "in");
            log.info("in hwctrl_gpioDirection isSuccess=" + isSuccess);*/
            //传送带
            Socket conveyer = null;
            Socket doorA = null;
            Socket doorB = null;
            //处理中断逻辑
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    byte[] data = new byte[1024];
                    PrintWriter out = new PrintWriter(client_socket.getOutputStream());
                    int len = client_socket.getInputStream().read(data);
                    Integer workMode = DOOR_MODE_CACHE.getIfPresent(RedisKeyEnum.KEY_REMOTE_CONTROLL.getCode());
                    if (workMode != 1) {
                        log.info("非核验模式");
                        continue;
                    }
                    if (len > 0) {

                        byte[] read = new byte[len];
                        System.arraycopy(data, 0, read, 0, len);
//                        final String strData = ByteUtil.bytesToHexString(read);
//                        final String strData = new String(read);


                        StringBuilder sb = new StringBuilder();
                        sb.append("起始位到数据长度位:");
                        byte[] bytes_1 = new byte[5];
                        System.arraycopy(read, 0, bytes_1, 0, bytes_1.length);
                        sb.append(bytesToHexString(bytes_1));
                        sb.append("\n");
                        int dataLen = bytes_1[3] << 2 | bytes_1[4] & 0xFF;
                        sb.append("数据内容长度:");
                        sb.append(dataLen);
                        sb.append("\n");
                        sb.append("数据内容:");
                        byte[] bytes_2 = new byte[dataLen];
                        System.arraycopy(read, 5, bytes_2, 0, dataLen);
                        sb.append(new String(bytes_2));
                        sb.append("\n");
                        sb.append("校验位:");
                        sb.append(read[read.length - 1]);

                        if (true) {
                            return;
                        }

                        String str = new String(data, 0, len);
                        log.info("人脸机IP:" + client_socket.getInetAddress() + ",人脸机端口:" + client_socket.getPort() + ",人脸数据:" + str);
                        int startIndex = str.indexOf("{");
//                    log.info("startIndex:" + startIndex);
                        int endIndex = str.lastIndexOf("}");
//                    log.info("endIndex:" + endIndex);
                        str = str.substring(startIndex, endIndex + 1);
                        FaceMessage faceMessage = JSON.parseObject(str, FaceMessage.class);
                        String deviceType = faceMessage.getDeviceType();
                        GatePassRecord gatePassRecordDTO = getGatePassRecordDTO(faceMessage);
                        gatePassRecordDTO.setFacePassTime(new Date());
                        //权限验证失败
                        if ("N".equals(faceMessage.getResult())) {
                            VoicePlayerUtil.voicePlay(1);
                            log.info("语音：人脸核验失败，禁止通行-182");
                            sendToFace(out, "3", "权限认证失败");
                            continue;
                        }

                        //如果有人进入，那么插入redis一个标记,15s钟
                        HASHUMAN_CACHE.put("hasHuman", 1);

                        if (UserTypeEnum.USER_TYPE_5.getCode().equals(faceMessage.getEmpType())) {
                            //供应商
                            String AGkey = RedisKeyEnum.KEY_AI_GY.getCode();
                            String modelPath = AI_CACHE.getIfPresent(AGkey);
                            int count = 0;
                            while (StrUtil.isEmpty(modelPath)) {
                                if (count > 10) {
                                    break;
                                }
                                TimeUnit.MILLISECONDS.sleep(400);
                                modelPath = AI_CACHE.getIfPresent(AGkey);
                                count++;
                                log.info("count==" + count);
                            }

                            if (!StringUtils.isNoneEmpty(modelPath)) {
                                if (!"已穿访客工衣".equals(modelPath)) {
                                    //未穿访客工衣
                                    VoicePlayerUtil.voicePlay(15);
                                    log.info("语音：未穿供应商马甲，禁止通行-194");
                                    gatePassRecordDTO.setStatus("2");
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_9.getCode());
                                    gatePassRecordDTO.setAlarmTime(new Date());
                                    sendGatePassRecord(gatePassRecordDTO);

                                    //删除redis中有人的标记
                                    HASHUMAN_CACHE.invalidate("hasHuman");
                                    AI_CACHE.invalidate(AGkey);
                                    continue;
                                }
                                //清除5s内校验AI识别的供应商马甲的缓存
                                CHECK_MODELPATH_CACHE.invalidateAll();
                            }
                        }
                        //判断是否有尾随
                        int aIalarm_fallow = readAIalarm();
                        if (aIalarm_fallow > 0) {
                            if ("in".equals(deviceType)) {
                                if (aIalarm_fallow == 101) {
                                    //尾随-入口-门外警告
                                    VoicePlayerUtil.voicePlay(18);
                                    log.info("语音：门外警告-发现尾随，请退出-188");
                                    boolean deleteAIalarmRet = deleteAIalarm();
                                    gatePassRecordDTO.setStatus("2");
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_11.getCode());
                                    gatePassRecordDTO.setAlarmTime(new Date());
                                    gatePassRecordDTO.setAiAlarmImgBase64(AI_CACHE.getIfPresent(RedisKeyEnum.KEY_AI_ALARM.getCode() + ":IMG"));
                                    sendGatePassRecord(gatePassRecordDTO);
                                    sendToFace(out, "6", "请尾随人员退出");
                                    //删除redis中有人的标记
                                    HASHUMAN_CACHE.invalidate("hasHuman");
                                    AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                    continue;
                                }
                            } else {
                                if (aIalarm_fallow == 103) {
                                    //尾随-出口-门外告警
                                    VoicePlayerUtil.voicePlay(18);
                                    log.info("语音：出口-门外警告-发现尾随，请退出-203");
                                    boolean deleteAIalarmRet = deleteAIalarm();
                                    gatePassRecordDTO.setStatus("2");
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_11.getCode());
                                    gatePassRecordDTO.setAlarmTime(new Date());
                                    gatePassRecordDTO.setAiAlarmImgBase64(AI_CACHE.getIfPresent(RedisKeyEnum.KEY_AI_ALARM.getCode() + ":IMG"));
                                    sendGatePassRecord(gatePassRecordDTO);
                                    sendToFace(out, "6", "请尾随人员退出");
                                    //删除redis中有人的标记
                                    HASHUMAN_CACHE.invalidate("hasHuman");
                                    AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                    continue;
                                }
                            }
                        }
                        if ("in".equals(deviceType)) {
                            doorA = new Socket(gateAIp, gateAPort);
                            doorB = new Socket(gateBIp, gateBPort);
                        } else {
                            doorA = new Socket(gateBIp, gateAPort);
                            doorB = new Socket(gateAIp, gateBPort);
                        }
                        sendToFace(out, "1", "人脸核验完成，继续核验中");
                        VoicePlayerUtil.voicePlay(9);
                        log.info("语音：核验中-242");
                        //给另一侧人脸机发1：通行中、请等待 加锁
                        if ("in".equals(deviceType)) {
                            sendtoFaceClient(faceBIp, "1", "通行中，请等待");
                        } else {
                            sendtoFaceClient(faceAIp, "1", "通行中，请等待");
                        }
                        //是否有物品要传送
                        long a1 = System.currentTimeMillis();
                        Set<Double> deviceWeightData;
                        if ("in".equals(deviceType)) {
                            deviceWeightData = NorcoAPIUtil.getDeviceWeightData(1);
                        } else {
                            deviceWeightData = NorcoAPIUtil.getDeviceWeightData(2);
                        }
                        long a2 = System.currentTimeMillis();
                        log.info("称重耗时:" + (a2 - a1));
                        //是否有物品
                        boolean hasGoods = false;
                        if (deviceWeightData != null && deviceWeightData.size() > 0) {
                            hasGoods = true;
                            //有物品传送
                            List<Double> weightList = new ArrayList<>(deviceWeightData);
                            double min_weight = weightList.get(0);
                            log.info("min_weight:" + min_weight);
                            double max_weight = weightList.get(weightList.size() - 1);
                            log.info("max_weight:" + max_weight);
                            gatePassRecordDTO.setWeight(new BigDecimal(max_weight));
                            //判断重量是否正常
                            log.info("获取重量开始：" + LocalTime.now());
                            GatePassWeightParamVo weightCorrect1 = checkWeight(min_weight);
                            GatePassWeightParamVo weightCorrect2 = checkWeight(max_weight);
                            log.info("获取重量结束：" + LocalTime.now());
                            //校验称重信息
                            if (weightCorrect1 == null || weightCorrect2 == null) {
                                VoicePlayerUtil.voicePlay(2);
                                log.info("语音：物品重量不正确，禁止通行-272");
                                sendToFace(out, "3", "物品重量不匹配");
                                //给另一侧人脸机发消息解锁
                                unlockAnother(deviceType, "3", "");
                                gatePassRecordDTO.setStatus("2");
                                gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_1.getCode());
                                gatePassRecordDTO.setAlarmTime(new Date());
                                sendGatePassRecord(gatePassRecordDTO);

                                //删除redis中有人的标记
                                HASHUMAN_CACHE.invalidate("hasHuman");
                                AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                continue;
                            }
                            //给PLC指令,传送物品到扫码位置
                            log.info("给PLC指令,传送物品到扫码位置");
                            conveyer = new Socket(gatePassSetVo.getPclIp(), 502);
                            SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M6.getCode());
                            log.info("一开始给传送带发送命令M6初始化");
                            Thread.sleep(200);
                            if ("in".equals(deviceType)) {
                                SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M0.getCode());
                                log.info("给传送带发送命令M0");
                            } else {
                                SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M4.getCode());
                                log.info("给传送带发送命令M4");
                            }
                            //核验token二维码、手机二维码、称重信息、待检区人数
                            //1:手机,2:token,3:手机+token
                            Integer type = weightCorrect1.getType();
                            log.info("重量组合type：" + type);
                            //获取手机二维码
                            String phone_QR_code = "";
                            //获取token二维码
                            String token_QR_code = "";
                            if ("in".equals(deviceType)) {
                                if (type == 1 || type == 3) {
                                    //获取手机二维码
                                    phone_QR_code = NorcoAPIUtil.getDeviceData(1);
                                }
                                if (type == 2 || type == 3) {
                                    //获取token二维码
                                    token_QR_code = NorcoAPIUtil.getDeviceData(2);
                                }
                            } else {
                                if (type == 1 || type == 3) {
                                    //获取手机二维码
                                    phone_QR_code = NorcoAPIUtil.getDeviceData(3);
                                }
                                if (type == 2 || type == 3) {
                                    //获取token二维码
                                    token_QR_code = NorcoAPIUtil.getDeviceData(4);
                                }
                            }
                            if (type == 1 || type == 3) {
                                if (StringUtils.isEmpty(phone_QR_code)) {
                                    VoicePlayerUtil.voicePlay(3);
                                    log.error("扫码拿不到手机二维码");
                                    sendtoFaceClient(faceBIp, "6", "扫码拿不到手机二维码");
                                    sendtoFaceClient(faceAIp, "6", "扫码拿不到手机二维码");
                                    if ("in".equals(deviceType)) {
                                        SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M7.getCode());
                                        log.info("给传送带发送命令M7");
                                    } else {
                                        SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M8.getCode());
                                        log.info("给传送带发送命令M8");
                                    }

                                    //删除redis中有人的标记
                                    HASHUMAN_CACHE.invalidate("hasHuman");
                                    AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                    continue;
                                }
                            }
                            if (type == 2 || type == 3) {
                                if (StringUtils.isEmpty(token_QR_code)) {
                                    VoicePlayerUtil.voicePlay(4);
                                    log.error("扫码拿不到tokenid");
                                    sendtoFaceClient(faceBIp, "6", "扫码拿不到tokenid");
                                    sendtoFaceClient(faceAIp, "6", "扫码拿不到tokenid");
                                    if ("in".equals(deviceType)) {
                                        SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M7.getCode());
                                        log.info("给传送带发送命令M7");
                                    } else {
                                        SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M8.getCode());
                                        log.info("给传送带发送命令M8");
                                    }

                                    //删除redis中有人的标记
                                    HASHUMAN_CACHE.invalidate("hasHuman");
                                    AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                    continue;
                                }
                            }
                            if (!checkWeightTwice(deviceType, out, gatePassRecordDTO)) {
                                log.error("再次称重，物品重量不匹配-390");
                                if ("in".equals(deviceType)) {
                                    SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M7.getCode());
                                    log.info("传送带从A门退出物品-M7");
                                } else {
                                    SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M8.getCode());
                                    log.info("传送带从B门退出物品-M8");
                                }

                                //删除redis中有人的标记
                                HASHUMAN_CACHE.invalidate("hasHuman");
                                AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                continue;
                            }
                            if (type == 1 || type == 3) {
                                if (!StringUtils.isEmpty(phone_QR_code)) {
                                    log.info("扫码获取手机二维码:" + phone_QR_code);
                                    gatePassRecordDTO.setPhoneQRcode(phone_QR_code);
                                    String mobilePincode = faceMessage.getMobilePinCode() + ";" + faceMessage.getEmpNo();
                                    log.info("人脸机返回的二维码和员工编号：" + mobilePincode);
                                    //校验二维码
                                    String[] mobilePincodeSplit = mobilePincode.split(";");
                                    //校验手机二维码
                                    boolean checkMobilePincode = false;
                                    for (String s : mobilePincodeSplit) {
                                        if (phone_QR_code.equalsIgnoreCase(s)) {
                                            checkMobilePincode = true;
                                            break;
                                        }
                                    }
                                    if (!checkMobilePincode) {
                                        VoicePlayerUtil.voicePlay(3);
                                        log.info("语音：手机二维码验证失败，禁止通行-403");
                                        sendToFace(out, "3", "手机二维码不匹配");
                                        if ("in".equals(deviceType)) {
                                            SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M7.getCode());
                                            log.info("传送带从A门退出物品-M7");
                                        } else {
                                            SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M8.getCode());
                                            log.info("传送带从B门退出物品-M8");
                                        }
                                        //给另一侧人脸机发消息解锁
                                        unlockAnother(deviceType, "3", "");
                                        gatePassRecordDTO.setStatus("2");
                                        gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_2.getCode());
                                        gatePassRecordDTO.setAlarmTime(new Date());
                                        sendGatePassRecord(gatePassRecordDTO);

                                        //删除redis中有人的标记
                                        HASHUMAN_CACHE.invalidate("hasHuman");
                                        AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                        continue;
                                    }
                                }
                            }
                            if (type == 2 || type == 3) {
                                if (!StringUtils.isEmpty(token_QR_code)) {
                                    log.info("扫码获取token二维码:" + token_QR_code);
                                    gatePassRecordDTO.setTokenQRCode(token_QR_code);
                                    //校验token二维码
                                    boolean checkTokenID = false;
                                    String tokenID = faceMessage.getTokenID();
                                    log.info("人脸机返回的tokenID：" + tokenID);
                                    if (!token_QR_code.equalsIgnoreCase(tokenID)) {
                                        VoicePlayerUtil.voicePlay(4);
                                        log.info("语音“令牌二维码验证失败，禁止通行-431");
                                        sendToFace(out, "3", "token二维码不匹配");
                                        if ("in".equals(deviceType)) {
                                            SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M7.getCode());
                                            log.info("传送带从A门退出物品-M7");
                                        } else {
                                            SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M8.getCode());
                                            log.info("传送带从B门退出物品-M8");
                                        }
                                        //给另一侧人脸机发消息解锁
                                        unlockAnother(deviceType, "3", "");
                                        gatePassRecordDTO.setStatus("2");
                                        gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_3.getCode());
                                        gatePassRecordDTO.setAlarmTime(new Date());
                                        sendGatePassRecord(gatePassRecordDTO);

                                        //删除redis中有人的标记
                                        HASHUMAN_CACHE.invalidate("hasHuman");
                                        AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                                        continue;
                                    }
                                }
                            }
                        }
                        //提示：验证通过请通行！
                        //A门闸机打开，通行人进入
                        log.info("进口闸机打开，通行人进入");
                        sendCommandToDoor(doorA, DoorCommandEnum.doorCommand6.getCode());
                        gatePassRecordDTO.setGateOpenTime1(new Date());
                        log.info("doorA: 01：常关；11：进向自由、出向自由-443");
                        VoicePlayerUtil.voicePlay(10);
                        log.info("语音：核验通过，请通行-456");

                        sendToFace(out, "2", "核验通过请通行");

                        //清空红外尾随数据
                        NorcoAPIUtil.gpiohwMap.clear();

//                            sendtoAllClient("5", "通行中，请等待");
                        if ("in".equals(deviceType)) {
                            //设置尾随红外开始监听
                            NorcoAPIUtil.gpiohwMap.put(InitBaseInfo.ipAddress + ":gpio:ws:124", 1);
                            sendtoFaceClient(faceBIp, "5", "通行中，请等待");
                            sendtoFaceClient(faceAIp, "5", "核验通过，请通行");
                        } else {
                            //设置尾随红外开始监听
                            NorcoAPIUtil.gpiohwMap.put(InitBaseInfo.ipAddress + ":gpio:ws:125", 1);
                            sendtoFaceClient(faceBIp, "5", "核验通过，请通行");
                            sendtoFaceClient(faceAIp, "5", "通行中，请等待");
                        }
                        if (hasGoods) {
                            //给PLC指令传送物品到B门暂停位置
                            log.info("给PLC指令传送物品到B门暂停位置-457");
                            if ("in".equals(deviceType)) {
                                SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M1.getCode());
                                log.info("给传送带发送命令M1-460");
                            } else {
                                SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M5.getCode());
                                log.info("给传送带发送命令M5-463");
                            }
                        }
                        //入口内侧红外感应检测到信号
                        long beginTime = System.currentTimeMillis();
                        String enterFlag = "";
                        while (!"IN".equals(readInfraredIn(doorA))) {
                            long currentTime = System.currentTimeMillis();
                            long diff = (currentTime - beginTime) / 1000;
                            if (diff > 5) {
                                log.error("超时未进去（5秒）");
                                sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                                log.info("doorA: 01：常关；22：进向禁止、出向禁止-475");
                                Thread.sleep(1000);
                                VoicePlayerUtil.voicePlay(16);
                                log.info("语音：超时未进入-482");
                                enterFlag = "NOT_IN";
                                break;
                            }
                        }
                        Thread.sleep(800);
                        sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                        Thread.sleep(50);
                        sendCommandToDoor(doorA, DoorCommandEnum.doorCommand5.getCode());
                        log.info("doorA: 01：常关；12：进向禁止、出向自由-486");
                        if ("NOT_IN".equals(enterFlag)) {
                            sendtoFaceClient(faceBIp, "6", "未进入通道");
                            sendtoFaceClient(faceAIp, "6", "未进入通道");
                            sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                            log.info("doorB: 01：常关；22：进向禁止、出向禁止-489");
                            Thread.sleep(1000);
                            sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                            log.info("doorA: 01：常关；22：进向禁止、出向禁止-492");
                            if (hasGoods) {
                                SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M3.getCode());
                                log.info("给传送带发送命令M3-495");
                            }

                            //删除redis中有人的标记
                            HASHUMAN_CACHE.invalidate("hasHuman");
                            AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                            //设置尾随红外结束监听
                            if ("in".equals(deviceType)) {
                                NorcoAPIUtil.gpiohwMap.put(InitBaseInfo.ipAddress + ":gpio:ws:124", 2);
                            } else {
                                NorcoAPIUtil.gpiohwMap.put(InitBaseInfo.ipAddress + ":gpio:ws:124", 2);
                            }

                            continue;
                        }
                        if ("in".equals(deviceType)) {
                            sendtoFaceClient(faceAIp, "5", "通行中，请等待");
                        } else {
                            sendtoFaceClient(faceBIp, "5", "通行中，请等待");
                        }
                        sendCommandToDoor(doorB, DoorCommandEnum.doorCommand5.getCode());
                        log.info("doorB: 01：常关；11：进向禁止、出向自由");

                        //设置尾随红外结束监听
                        int hwws = 1;
                        log.info("尾随结果：{}", NorcoAPIUtil.gpiohwMap);

                        if ("in".equals(deviceType)) {
                            NorcoAPIUtil.gpiohwMap.put(InitBaseInfo.ipAddress + ":gpio:ws:124", 2);
                            if (NorcoAPIUtil.gpiohwMap.get(InitBaseInfo.ipAddress + ":gpio:124") != null &&
                                    NorcoAPIUtil.gpiohwMap.get(InitBaseInfo.ipAddress + ":gpio:124") > 1) {
                                hwws = 2;
                                log.info("尾随结果hwws：{}", hwws);
                            }
                        } else {
                            NorcoAPIUtil.gpiohwMap.put(InitBaseInfo.ipAddress + ":gpio:ws:125", 2);

                            if (NorcoAPIUtil.gpiohwMap.get(InitBaseInfo.ipAddress + ":gpio:125") != null &&
                                    NorcoAPIUtil.gpiohwMap.get(InitBaseInfo.ipAddress + ":gpio:125") > 1) {
                                hwws = 2;
                                log.info("尾随结果hwws：{}", hwws);
                            }
                        }


                        boolean warnFlag = false;
                        int passRet = 0;
                        //出口内侧红外感应检测到信号
                        while (!"IN".equals(readInfraredIn(doorB))) {
                            if ("OUT".equals(readInfraredOut(doorA))) {
                                //人从A门退出
                                //B门进出向禁止
                                sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                                log.info("doorB: 01：常关；22：进向禁止、出向禁止-473");
                                Thread.sleep(1000);
                                //A门进出向禁止
                                sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                                log.info("doorA: 01：常关；22：进向禁止、出向禁止-477");
                                passRet = 1;
                                sendtoFaceClient(faceBIp, "3", "");
                                sendtoFaceClient(faceAIp, "3", "");
                                if (hasGoods) {
                                    SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M3.getCode());
                                    log.info("给传送带发送命令M3-482");
                                }
                                break;
                            }
                            long currentTime = System.currentTimeMillis();
                            long diff = (currentTime - beginTime) / 1000;
                            if (diff > 15) {
                                //超时（15秒）未出去
                                log.error("超时（15秒）未通过B门-502");
                                enterFlag = "NOT_OUT";
                                if (hasGoods) {
                                    SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M3.getCode());
                                    log.info("给传送带发送命令M3-539");
                                }
                                VoicePlayerUtil.voicePlay(13);
                                log.info("语音：请勿在通道内滞留-515");
                                break;
                            }
                            //读取金属探测结果
                            int metal_detect = NorcoAPIUtil.mNorcoAPI.hwctrl_gpioRead(122);
                            if (metal_detect > 0) {//有金属
                                //A/B门闸机打开，让通行人出去
                                VoicePlayerUtil.voicePlay(8);
                                log.info("语音：违规携带金属物品，禁止通行-550");
                            }
                            //从redis读取AI报警结果
                            int aIalarmRet = readAIalarm();
                            boolean realAIalarm = false;
                            if (aIalarmRet > 0) {
                                log.error("AI告警(599)：" + aIalarmRet);
                                //尾随-中间区域，需要告警
                                if (aIalarmRet == 102 || aIalarmRet == 104) {
                                    aIalarmRet = 5;
                                }
                                if ("in".equals(deviceType)) {
                                    if (aIalarmRet == 101) {
                                        aIalarmRet = 5;
                                        realAIalarm = true;
                                    }
                                } else {
                                    if (aIalarmRet == 103) {
                                        aIalarmRet = 5;
                                        realAIalarm = true;
                                    }
                                }
                                if (aIalarmRet != 6) {
                                    if ("in".equals(deviceType)) {
                                        if (aIalarmRet != 103) {
                                            realAIalarm = true;
                                            VoicePlayerUtil.voicePlay(aIalarmRet);
                                            log.error("AI告警-624，aIalarmRet" + aIalarmRet);
                                        }
                                    } else {
                                        if (aIalarmRet != 101) {
                                            realAIalarm = true;
                                            VoicePlayerUtil.voicePlay(aIalarmRet);
                                            log.error("AI告警-630，aIalarmRet" + aIalarmRet);
                                        }
                                    }
                                }
                                log.info("634-aIalarmRet:" + aIalarmRet + ",realAIalarm:" + realAIalarm);
                            }
                            //有红外尾随感应
                            if (hwws == 2 && passRet == 0) {
                                if (aIalarmRet != 5) {//防止语音告警两次
                                    VoicePlayerUtil.voicePlay(5);
                                }
                                aIalarmRet = 5;
                                realAIalarm = true;

                                log.info("红外尾随感应-633");
                            }
                            //有金属、AI告警的情况控制闸机、传送带
                            if (metal_detect > 0 || (aIalarmRet > 0 && realAIalarm)) {
                                //B门进出向禁止
                                sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                                log.info("doorB: 01：常关；22：进向禁止、出向禁止-598");
                                if (aIalarmRet == 5) {//尾随
                                    //A门常关、出向自由、进向禁止
                                    sendCommandToDoor(doorA, DoorCommandEnum.doorCommand5.getCode());
                                } else {
                                    //A门常开、出向自由、进向禁止
                                    sendCommandToDoor(doorA, DoorCommandEnum.doorCommand2.getCode());
                                }
                                log.info("doorA: 01：常关；12：进向禁止、出向自由-601");
                                if (hasGoods) {
                                    SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M3.getCode());
                                    log.info("给传送带发送命令M3-620");
                                }
                                //检测是否退出通道
                                beginTime = System.currentTimeMillis();
                                while (!"OUT".equals(readInfraredOut(doorA))) {
                                    currentTime = System.currentTimeMillis();
                                    diff = (currentTime - beginTime) / 1000;
                                    if (diff > 15) {
                                        //超时未出来
                                        VoicePlayerUtil.voicePlay(12);
                                        log.info("AI/金属探测门告警，超时15秒未出来，语音：请退出通道-597");
                                        enterFlag = "NOT_OUT";
                                        break;
                                    }
                                    if ("OUT".equals(readInfraredOut(doorB))) {
                                        //闸机为了防止夹住脚，就算红灯也会让人通过
                                        //B门进出向禁止
                                        sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                                        log.info("doorB: 01：常关；22：进向禁止、出向禁止-621");
                                        //A门进出向禁止
                                        sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                                        log.info("doorA: 01：常关；22：进向禁止、出向禁止-625");
                                        sendtoFaceClient(faceBIp, "6", "已离开通道");
                                        sendtoFaceClient(faceAIp, "6", "已离开通道");
                                        break;
                                    }
                                }
                                if (aIalarmRet > 0) {
                                    boolean deleteAIalarmRet = deleteAIalarm();
                                }
                                sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                                log.info("doorB: 01：常关；22：进向禁止、出向禁止-643");
                                Thread.sleep(1000);
                                if (aIalarmRet == 5) {//尾随
                                    sendCommandToDoor(doorA, DoorCommandEnum.doorCommand5.getCode());
                                    log.info("doorA: 01：常关；12：进向禁止、出向自由-639");
                                } else {
                                    sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                                    log.info("doorA: 01：常关；22：进向禁止、出向禁止-642");
                                }
                                warnFlag = true;
                                gatePassRecordDTO.setStatus("2");
                                if (aIalarmRet == 5) {
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_10.getCode());
                                } else if (aIalarmRet == 6) {
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_6.getCode());
                                } else if (aIalarmRet == 7) {
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_7.getCode());
                                } else if (aIalarmRet == 8) {
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_8.getCode());
                                } else if (aIalarmRet == 14) {
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_5.getCode());
                                }
                                if (metal_detect > 0) {
                                    gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_4.getCode());
                                }
                                gatePassRecordDTO.setAlarmTime(new Date());
                                gatePassRecordDTO.setAiAlarmImgBase64(AI_CACHE.getIfPresent(RedisKeyEnum.KEY_AI_ALARM.getCode() + ":IMG"));
                                sendGatePassRecord(gatePassRecordDTO);
                                break;
                            }
                        }
                        gatePassRecordDTO.setGateOpenTime2(new Date());
                        gatePassRecordDTO.setCostTime((gatePassRecordDTO.getGateOpenTime2().getTime() - gatePassRecordDTO.getGateOpenTime1().getTime()) / 1000);
                        if (passRet == 1) {
                            //人直接从A门通过，未通过B门
                            //删除redis中有人的标记
                            HASHUMAN_CACHE.invalidate("hasHuman");
                            AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                            continue;
                        }
                        log.info("enterFlag-658: " + enterFlag);
                        if ("NOT_OUT".equals(enterFlag)) {
                            log.info("超时未通过B门，A门出向自由、进向禁止，B门进出向禁止");
                            //B门进出向禁止
                            sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                            log.info("doorB: 01：常关；22：进向禁止、出向禁止-679");
                            //A门出向自由、进向禁止
                            sendCommandToDoor(doorA, DoorCommandEnum.doorCommand2.getCode());
                            log.info("doorA: 00：常开；12：进向禁止、出向自由-682");
                            int i = 0;
                            while (!"OUT".equals(readInfraredOut(doorA))) {
                                Thread.sleep(100);
                                //以下注释的几行是人脸机通过手动按钮进行解锁时，仍然扫不了脸的bug修复，如果后期提到了这个bug，打开测试没问题在发包
                                /*String faceReset = redisCache.getCacheObject("faceReset");
                                if("1".equals(faceReset)) {
                                    redisCache.deleteObject("faceReset");
                                    i++;
                                    break;
                                }*/
                            }
                            /*if(i>0){
                                continue;
                            }*/
                            sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                            log.info("doorB: 01：常关；22：进向禁止、出向禁止-687");
                            Thread.sleep(1000);
                            sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                            log.info("doorA: 01：常关；22：进向禁止、出向禁止-690");
                            sendtoFaceClient(faceBIp, "3", "");
                            sendtoFaceClient(faceAIp, "3", "");

                            //删除redis中有人的标记
                            HASHUMAN_CACHE.invalidate("hasHuman");
                            AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                            continue;
                        }
                        //有告警
                        if (warnFlag) {
                            sendtoFaceClient(faceBIp, "3", "");
                            log.info("给B人脸机发送：3（有物品）-695");
                            sendtoFaceClient(faceAIp, "3", "");
                            log.info("给A人脸机发送：3（有物品）-697");

                            //删除redis中有人的标记
                            HASHUMAN_CACHE.invalidate("hasHuman");
                            AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                            continue;
                        }
                        //红外感应到人，既没有AI告警，也没有探测到金属
                        //外侧红外感应检测到信号
                        if (hasGoods) {
                            SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M2.getCode());
                            log.info("给传送带发送命令M2-707");
                        }
                        beginTime = System.currentTimeMillis();
                        while (!"OUT".equals(readInfraredOut(doorB))) {
                            long currentTime = System.currentTimeMillis();
                            long diff = (currentTime - beginTime) / 1000;
                            if (diff > 15) {
                                //超时未出来
                                VoicePlayerUtil.voicePlay(13);
                                log.info("语音：请勿在通道内滞留-666");
                                break;
                            }

                        }
                        VoicePlayerUtil.voicePlay(17);
                        log.info("语音:一路顺风-762");
                        boolean deleteAIalarmRet = deleteAIalarm();
                        sendCommandToDoor(doorA, DoorCommandEnum.doorCommand1.getCode());
                        log.info("doorA: 01：常关；22：进向禁止、出向禁止");
                        Thread.sleep(1000);
                        sendCommandToDoor(doorB, DoorCommandEnum.doorCommand1.getCode());
                        log.info("doorB: 01：常关；22：进向禁止、出向禁止-732");
                        sendtoFaceClient(faceBIp, "6", "已离开通道");
                        sendtoFaceClient(faceAIp, "6", "已离开通道");
                        closeSocket(doorA, doorB, conveyer);
                        showUserList();
                        gatePassRecordDTO.setStatus("1");
                        sendGatePassRecord(gatePassRecordDTO);
                    }
                } catch (Exception e) {
                    log.error("通行异常: {}", e.getMessage());
                } finally {
                    sendtoFaceClient(faceBIp, "6", "已离开通道");
                    sendtoFaceClient(faceAIp, "6", "已离开通道");

                    //删除redis中有人的标记
                    HASHUMAN_CACHE.invalidate("hasHuman");
                    AI_CACHE.invalidate(RedisKeyEnum.KEY_AI_GY.getCode());
                    //清空红外尾随数据
                    //NorcoAPIUtil.gpiohwMap.clear();
                    try {
                        if (conveyer != null) {
                            conveyer.close();
                        }
                    } catch (IOException e) {
                        log.error("conveyer close() error: [{}]", e.getMessage(), e);
                    }
                    try {
                        if (doorA != null) {
                            doorA.close();
                        }
                    } catch (IOException e) {
                        log.error("doorA close() error: [{}]", e.getMessage(), e);
                    }
                    try {
                        if (doorB != null) {
                            doorB.close();
                        }
                    } catch (IOException e) {
                        log.error("doorB close() error: [{}]", e.getMessage(), e);
                    }
                }
            }

        }

        /**
         * 二次校验重量
         *
         * @param deviceType
         * @return
         * @throws InterruptedException
         */
        private boolean checkWeightTwice(String deviceType, PrintWriter out, GatePassRecord gatePassRecordDTO) throws InterruptedException {
            boolean ret = true;
            Set<Double> deviceWeightData;
            if ("in".equals(deviceType)) {
                deviceWeightData = NorcoAPIUtil.getDeviceWeightData(1);
            } else {
                deviceWeightData = NorcoAPIUtil.getDeviceWeightData(2);
            }
            //有物品传送
            List<Double> weightList = new ArrayList<>(deviceWeightData);
            double min_weight = weightList.get(0);
            log.info("min_weight-923:" + min_weight);
            double max_weight = weightList.get(weightList.size() - 1);
            log.info("max_weight-925:" + max_weight);
            //判断重量是否正常
            log.info("获取重量开始-927：" + LocalTime.now());
            GatePassWeightParamVo weightCorrect1 = checkWeight(min_weight);
            GatePassWeightParamVo weightCorrect2 = checkWeight(max_weight);
            log.info("获取重量结束-930：" + LocalTime.now());
            //校验称重信息
            if (weightCorrect1 == null || weightCorrect2 == null) {
                VoicePlayerUtil.voicePlay(2);
                log.info("语音：物品重量不正确，禁止通行-934");
                sendToFace(out, "3", "物品重量不匹配");
                //给另一侧人脸机发消息解锁
                unlockAnother(deviceType, "3", "");
                gatePassRecordDTO.setStatus("2");
                gatePassRecordDTO.setAlarmType(ExceptionEnum.EXCEPTION_1.getCode());
                gatePassRecordDTO.setAlarmTime(new Date());
                sendGatePassRecord(gatePassRecordDTO);
                ret = false;
            }
            return ret;
        }

        /**
         * 关闭socket
         *
         * @param doorA    A门
         * @param doorB    B门
         * @param conveyer 传送带
         */
        private void closeSocket(Socket doorA, Socket doorB, Socket conveyer) {
            log.info("closeSocket begin");
            try {
                if (conveyer != null) {
                    conveyer.close();
                }
            } catch (IOException e) {
                log.error("conveyer close() error: [{}]", e.getMessage(), e);
            }
            try {
                if (doorA != null) {
                    doorA.close();
                }
            } catch (IOException e) {
                log.error("doorA close() error: [{}]", e.getMessage(), e);
            }
            try {
                if (doorB != null) {
                    doorB.close();
                }
            } catch (IOException e) {
                log.error("doorB close() error: [{}]", e.getMessage(), e);
            }
            log.info("closeSocket end");
        }

        /**
         * 初始化PassRecordDTO
         *
         * @param faceRecognitionDTO 人脸机数据
         * @return GatePassRecordDTO
         */
        private GatePassRecord getGatePassRecordDTO(FaceMessage faceRecognitionDTO) {
            GatePassRecord gatePassRecordDTO = new GatePassRecord();
            gatePassRecordDTO.setPassTime(new Date());
            gatePassRecordDTO.setJobNo(faceRecognitionDTO.getEmpNo());
            gatePassRecordDTO.setUserName(faceRecognitionDTO.getEmpName());
            gatePassRecordDTO.setUserType(faceRecognitionDTO.getEmpType());
            gatePassRecordDTO.setPhoneNum(faceRecognitionDTO.getMobilePinCode());
            gatePassRecordDTO.setTokenNum(faceRecognitionDTO.getTokenID());
            gatePassRecordDTO.setDirection(faceRecognitionDTO.getDeviceType());
            gatePassRecordDTO.setDirection(faceRecognitionDTO.getDeviceType());
            gatePassRecordDTO.setIpAddress(InitBaseInfo.ipAddress);
            //通道信息
            GatePassSetVo gatePassSetVo = GuavaCache.PASSSET_CACHE.getIfPresent("passsetipInfo");
            gatePassRecordDTO.setThoroughfare(gatePassSetVo.getName());
            gatePassRecordDTO.setGatePassSetId(gatePassSetVo.getId());
            gatePassRecordDTO.setEntrance(gatePassSetVo.getOutInName());
            gatePassRecordDTO.setGatePassOutInId(gatePassSetVo.getGatePassOutInId());
            return gatePassRecordDTO;
        }

        /**
         * 读取AI告警结果
         */
        private int readAIalarm() {
            int aiAlarmFlag = 0;
            String modelPath = AI_CACHE.getIfPresent(RedisKeyEnum.KEY_AI_ALARM.getCode());
            if (modelPath != null) {
                switch (modelPath) {
                    case "尾随-入口-门外告警":
                        aiAlarmFlag = 101;
                        break;
                    case "尾随-入口-门内告警":
                        aiAlarmFlag = 102;
                        break;
                    case "尾随-出口-门外告警":
                        aiAlarmFlag = 103;
                        break;
                    case "尾随-出口-门内告警":
                        aiAlarmFlag = 104;
                        break;
                    case "跨越":
                        aiAlarmFlag = 6;
                        break;
                    case "弯腰":
                        aiAlarmFlag = 7;
                        break;
                    case "下蹲":
                        aiAlarmFlag = 7;
                        break;
                    case "举手过肩":
                        aiAlarmFlag = 14;
                    default:
                        break;
                }
            }
            return aiAlarmFlag;
        }

        /**
         * 删除AI告警结果
         */
        private boolean deleteAIalarm() {
            String AAkey = RedisKeyEnum.KEY_AI_ALARM.getCode();
            AI_CACHE.invalidate(AAkey);
            String AGkey = RedisKeyEnum.KEY_AI_GY.getCode();
            AI_CACHE.invalidate(AGkey);
            return true;
        }

        /**
         * 给闸机发送命令
         *
         * @param door    闸机
         * @param command 命令
         * @return 执行结果
         */
        private String sendCommandToDoor(Socket door, String command) {
            String str = SocketClientUtil.sendData(door, command);
            return str;
        }

        /**
         * 红外感应是否有人进入通道
         *
         * @param infrared 红外感应
         * @return 红外感应结果
         */
        public String readInfraredIn(Socket infrared) {
            String str = SocketClientUtil.sendData(infrared, "000006000006010303940008");
            //log.info("红外感应结果：" + str);
            String[] strArr = str.split(",");
            String lastStr = strArr[strArr.length - 1];
            lastStr = lastStr.replace("0x", "").trim();
            if (!"00".equals(lastStr)) {
                //log.info("十六进制：" + lastStr);
                //十六进制转成十进制
                int result_16 = Integer.parseInt(lastStr, 16);
                //log.info("十进制：" + result_16);
                //十进制转成二进制
                String result_2 = Integer.toBinaryString(result_16);
                //log.info("二进制：" + result_2);
                //获取第1位
                if ("1".equals(result_2.substring(result_2.length() - 1, result_2.length()))) {
                    //有人进入
                    log.info("有人进入-1092");
                    return "IN";
                }
            }
            return "";
        }

        /**
         * 红外感应是否有人离开通道
         *
         * @param infrared 红外感应
         * @return 红外感应结果
         */
        public String readInfraredOut(Socket infrared) {
            String str = SocketClientUtil.sendData(infrared, "000006000006010303940008");
            //og.info("红外感应结果：" + str);
            String[] strArr = str.split(",");
            String lastStr = strArr[strArr.length - 1];
            lastStr = lastStr.replace("0x", "").trim();
            if (!"00".equals(lastStr)) {
                //log.info("十六进制：" + lastStr);
                //十六进制转成十进制
                int result_16 = Integer.parseInt(lastStr, 16);
                //log.info("十进制：" + result_16);
                //十进制转成二进制
                String result_2 = Integer.toBinaryString(result_16);
                //log.info("二进制：" + result_2);
                if (result_2.length() >= 8) {
                    //获取倒数第8位
                    String reverse_8 = result_2.substring((result_2.length() - 8), (result_2.length() - 7));
                    if ("1".equals(reverse_8)) {
                        //有人出去
                        log.info("有人出去");
                        return "OUT";
                    }
                }
            }
            return "";
        }

        //读取尾随
        public String readTailgating(Socket infrared) {
            String str = SocketClientUtil.sendTailgatingData(infrared, DoorCommandEnum.doorCommand7.getCode());
            log.info("读取尾随感应结果：" + str);
            String[] strArr = str.split(",");
            String lastStr = strArr[strArr.length - 1];
            lastStr = lastStr.replace("0x", "").trim();
            if (!"00".equals(lastStr)) {
                //log.info("十六进制：" + lastStr);
                //十六进制转成十进制
                int result_16 = Integer.parseInt(lastStr, 16);
                //log.info("十进制：" + result_16);
                //十进制转成二进制
                String result_2 = Integer.toBinaryString(result_16);
                //log.info("二进制：" + result_2);
                if (result_2.length() >= 8) {
                    //获取倒数第8位
                    String reverse_8 = result_2.substring((result_2.length() - 8), (result_2.length() - 7));
                    if ("1".equals(reverse_8)) {
                        //有人出去
                        log.info("有人出去");
                        return "OUT";
                    }
                }
            }
            return "";
        }


        /**
         * 校验重量
         *
         * @param weight 重量
         * @return 重量
         */
        private GatePassWeightParamVo checkWeight(double weight) {
            List<GatePassWeightParamVo> mobileTokenweightList = MOBILE_TOKEN_WEIGHTLIST_CACHE.getIfPresent("mobileTokenweightList");
            for (GatePassWeightParamVo gatePassWeightParamVo : mobileTokenweightList) {
                if (weight >= gatePassWeightParamVo.getWeightMin() && weight <= gatePassWeightParamVo.getWeightMax()) {
                    return gatePassWeightParamVo;
                }
            }
            return null;
        }

        /**
         * 发送数据给人脸机
         *
         * @param out     输出流
         * @param code    返回码
         * @param message 返回消息
         */
        void sendToFace(PrintWriter out, String code, String message) {
            if (StringUtils.isNotEmpty(code) && ("3".equals(code) || "6".equals(code))) {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    log.error("睡眠2s异常");
                }
            }
            Map<String, String> responseMap = new HashMap<>();
            responseMap.put("code", code);
            responseMap.put("message", message);
            String responseStr = JSON.toJSONString(responseMap) + "###";
            out.write(responseStr);
            out.flush();
        }

        /**
         * 向后台发送通行记录
         *
         * @param gatePassRecordDTO 通行记录
         */
        void sendGatePassRecord(GatePassRecord gatePassRecordDTO) {
            log.info("sendGatePassRecord mqtt发送通行记录");
            String sendMessage = JSON.toJSONString(gatePassRecordDTO);
            mqttSendClient.publish(false, "wave-gate:passRecord", sendMessage);
        }

        /**
         * 给另一侧人脸机发解锁消息
         *
         * @param deviceType 进出方向
         * @param code       返回码
         * @param message    返回信息
         */
        void unlockAnother(String deviceType, String code, String message) {
            GatePassSetVo gatePassSetVo = GuavaCache.PASSSET_CACHE.getIfPresent("passsetipInfo");
            if ("in".equals(deviceType)) {
                sendtoFaceClient(gatePassSetVo.getOutFaceIp(), code, message);
            } else {
                sendtoFaceClient(gatePassSetVo.getInFaceIp(), code, message);
            }
        }
    }

    /**
     * 显示所有人脸机列表
     */
    private synchronized void showUserList() {
        log.info("*****人脸机列表****");
        log.info("在线人脸机数：" + clients.size());
        for (Map.Entry<String, Socket> user : clients.entrySet()) {
            log.info("人脸机,key:" + user.getKey() + ",value:" + user.getValue());
        }
    }

    /**
     * 转发消息给某个特定的人脸机
     *
     * @param ip      ip地址
     * @param code    返回码
     * @param message 返回信息
     */
    public static synchronized void sendtoFaceClient(String ip, String code, String message) {
        try {
            if (StringUtils.isNotEmpty(code) && ("3".equals(code) || "6".equals(code))) {
                TimeUnit.SECONDS.sleep(2);
            }
            Map<String, String> responseMap = new HashMap<>();
            responseMap.put("code", code);
            responseMap.put("message", message);
            String responseStr = JSON.toJSONString(responseMap) + "###";
            PrintWriter server_out = new PrintWriter(clients.get(ip).getOutputStream());
            server_out.write(responseStr);
            server_out.flush();
        } catch (Exception e) {
            log.error("sendtoFaceClient error:{}", e.getMessage());
        }
    }


}

